package cn.jingyuan.swan.cloud.core;

import cn.jingyuan.bee.exception.ErrorCode;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 通用错误码
 */
@Getter
@ToString
@AllArgsConstructor
public enum ExCode implements ErrorCode {

    /*
        错误码规则：
            1、错误码共 7 位字符串数字；
            2、第 1~2 位表示模块代码；
            3、第 3~7 位表示模块及模块内部错误码；
                3~4：子模块代码；
                5~7：子模块内错误码；

            特殊错误码：
                00xxxxx
                    0000000
                    0000999
                    0099999
     */

    /** 0000000：成功 */
    SUCCESS("0000000", "成功"),
    /** 0000999：警告 */
    WARNING("0000999", "警告"),
    /** 0099999：失败 */
    FAILURE("0099999", "失败"),

    /*
        00：系统级别
            00：http
            01：xx
            02：xx
            03：xx
            04：xx
            05：xx
            06：xx
            07：xx
            08：xx
            09：xx

            00：http 详细错误码
            --400
            --401
            --403
            --404
            --405
            --406
            --500
            --502
            --503
            --504

     */

    // 0000：http
    // OK("0000200", "成功"),
    BAD_REQUEST("0000400", "请求无效"),
    UNAUTHORIZED("0000401", "认证失败，请重新登录！"),
    FORBIDDEN("0000403", "权限不足，拒绝访问！"),
    NOT_FOUND("0000404", "访问地址不存在"),
    METHOD_NOT_ALLOWED("0000405", "请求方式不支持"),
    NOT_ACCEPTABLE("0000406", "服务器无法受理，请选择正确的请求方式！"),
    UNSUPPORTED_MEDIA_TYPE("0000415", "媒体类型不支持"),
    INTERNAL_SERVER_ERROR("0000500", "服务器错误"),
    BAD_GATEWAY("0000502", "网关错误"),
    SERVICE_UNAVAILABLE("0000503", "服务暂时无法访问"),
    GATEWAY_TIMEOUT("0000504", "网关超时"),


    // 0001：limit --> forbidden
    ACCESS_BLACK_LIMITED("0001001", "ip 或域名拒绝访问"),
    ACCESS_WHITE_LIMITED("0001002", "ip 或域名不在白名单内，拒绝访问！"),
    ACCESS_AUTHORITY_EXPIRED("0001003", "授权已过期，拒绝访问！"),
    ACCESS_UPDATING("0001004", "升级维护中，请稍后再试！"),
    ACCESS_DISABLED("0001005", "请求地址禁止访问"),
    ACCESS_NOT_OPEN("0001006", "请求地址拒绝访问"),


    // 0002：oauth
    INVALID_REQUEST("0002000", "无效的请求"),
    INVALID_CLIENT("0002001", "无效的客户端"),
    INVALID_GRANT("0002002", "无效的授权"),
    UNAUTHORIZED_CLIENT("0002003", "未经授权的客户端"),
    UNSUPPORTED_GRANT_TYPE("0002004", "授权类型错误或不受支持"),
    INVALID_SCOPE("0002005", "无效的授权范围"),
    INVALID_TOKEN("0002006", "无效的访问令牌"),
    EXPIRED_TOKEN("0002007", "访问令牌过期"),
    REDIRECT_URI_MISMATCH("0002008", "重定向地址不匹配"),
    UNSUPPORTED_RESPONSE_TYPE("0002009", "响应类型不支持"),


    // 0003：account
    ACCOUNT_EXIST("0003000", "账号已存在"),
    ACCOUNT_NOT_EXIST("0003001", "账号不存在"),
    BAD_CREDENTIALS("0003002", "账号或密码错误"),
    ACCOUNT_DISABLED("0003003", "账号已禁用"),
    ACCOUNT_LOCKED("0003004", "账号已锁定"),
    ACCOUNT_EXPIRED("0003005", "账号已过期"),
    CREDENTIALS_EXPIRED("0003006", "密码已过期"),


    // 0004：api
    API_ERROR("0004001", "请参考 api 文档");


    /** 内部高速缓存 */
    public static final Map<String, ExCode> CACHE_EX_CODES;

    // 初始化缓存
    static {
        ExCode[] codes = ExCode.values();
        Map<String, ExCode> exCodes = new HashMap<>(codes.length);
        for (ExCode code : codes) {
            exCodes.put(code.code, code);
        }
        // 构建只读 Map
        CACHE_EX_CODES = Collections.unmodifiableMap(exCodes);
    }

    /** 编码 */
    final String code;

    /** 编码消息 */
    final String codeMsg;

    /**
     * 查找并返回 <code>code</code> 对应的 {@link ExCode}，未查询到返回 <code>null</code>
     *
     * @param code 编码
     *
     * @return {@link ExCode} or <code>null</code>
     */
    public static ExCode codeOf(String code) {
        return CACHE_EX_CODES.get(code);
    }

    public static Map<String, ExCode> getExCodes() {
        Map<String, ExCode> codes = new HashMap<>(CACHE_EX_CODES.size());
        codes.putAll(CACHE_EX_CODES);
        return codes;
    }

    public static Map<String, ExCode> getCacheExCodes() {
        return CACHE_EX_CODES;
    }

    public static boolean exist(String code) {
        return CACHE_EX_CODES.containsKey(code);
    }

    public static boolean exist(ExCode code) {
        return CACHE_EX_CODES.containsKey(code.getCode());
    }

}
